package com.aries.ui.helper.navigation;

import com.aries.ui.util.StatusBarUtil;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.LifecycleObserver;
import ohos.accessibility.ability.AccessibleAbility;
import ohos.accessibility.ability.SoftKeyBoardController;
import ohos.accessibility.ability.SoftKeyBoardListener;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.ComponentTreeObserver;
import ohos.agp.components.TextField;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.window.dialog.CommonDialog;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.agp.window.service.Window;
import ohos.agp.window.service.WindowManager;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

import java.lang.ref.WeakReference;

/**
 * @Author XiaoMing
 * @Time 2021/4/20-15:44
 * @Describe * Function: 软键盘和虚拟导航栏统一设置
 * * Description:
 * * 1、2018-2-7 12:27:36 修改是否控制NavigationBar参数及对应java方法
 * * 2、2018-11-28 11:57:07 优化软键盘弹出关闭方案;增加相应监听回调;去掉是否控制导航栏方法
 * * 3、2018-11-28 13:53:41 新增软键盘控制相应静态方法--如开关软键盘
 * * 4、2018-12-3 17:44:59 修改设置padding逻辑避免部分情况计算底部padding错误问题
 * * 5、2019-2-25 14:00:37 将activity对象弱引用避免内存泄露;优化注册activity 销毁逻辑
 * * 6、2019-4-11 13:10:30 优化Dialog 参数定义{@link #KeyboardHelper(Ability, CommonDialog, int)}
 * * 7、2019-5-29 15:39:37 增加获取 findViewById(R.id.content) 非空判断避免系统空指针异常
 * * 8、2019-7-22 09:19:45 移除设置contentView相关with方法
 */
public class KeyboardHelper implements SoftKeyBoardListener {

    private WeakReference<Ability> mActivity;
    private WeakReference<Component> mContentView;
    private int mKeyMode = WindowManager.LayoutConfig.INPUT_STATE_UNSPECIFIED;
    /**
     * 显示软键盘的延迟时间
     */
    public static final int KEYBOARD_SHOW_DELAY_TIME = 300;
    /**
     * 判断软键盘开启的阈值
     */
    public final static int KEYBOARD_VISIBLE_THRESHOLD_DP = 100;
    /**
     * 记录contentView的距离底部padding
     */
    private int mPaddingBottom;
    /**
     * 保存软键盘历史开启状态
     */
    private boolean mIsKeyboardOpened = false;
    /**
     * 保存底部距顶部
     */
    private int mHeightDiff;
    /**
     * 软键盘开关状态转换回调--即有软键盘开关变化才会回调
     */
    private OnKeyboardVisibilityChangedListener mOnKeyboardVisibilityChangedListener;
    private boolean mLogEnable;
    /**
     * 目标Ability的根布局
     */
    private static int rootResId;
    /**
     * 焦点TextField
     */
    private int focusResId;
    /**
     * 软键盘是否弹出
     */
    private static boolean isKeyboardVisible;

    /**
     *
     */
    public interface OnKeyboardVisibilityChangedListener {

        /**
         * 软键盘开关状态转换回调--即有软键盘开关变化才会回调
         *
         * @param activity 当前Activity
         * @param isOpen 软键盘是否开启
         * @param heightDiff 预留让软件盘上移高度--给contentView累加设置的paddingBottom
         * @param navigationHeight 当前导航栏高度
         * @return true 监听一次即移除全局监听,false一直监听
         */
        boolean onKeyboardVisibilityChanged(Ability activity, boolean isOpen, int heightDiff, int navigationHeight);
    }

    /**
     * KeyboardHelper
     * @param activity Ability
     * @param rootResId 需要用到这个方法（必须要在xml根布局下添加  ohos:id="$+id:rootResId"）
     * @return KeyboardHelper
     * @exception IllegalArgumentException 非法参数异常
     */
    public static KeyboardHelper with(Ability activity, int rootResId) {
        KeyboardHelper.rootResId = rootResId;
        if (activity == null) {
            throw new IllegalArgumentException("Activity不能为null");
        }
        return new KeyboardHelper(activity, rootResId);
    }

    /**
     * KeyboardHelper
     * @param activity Ability
     * @param dialog dialog
     * @param rootResId  rootResId
     * @return KeyboardHelper
     * @exception IllegalArgumentException 非法参数异常
     */
    public static KeyboardHelper with(Ability activity, CommonDialog dialog, int rootResId) {
        KeyboardHelper.rootResId = rootResId;
        if (activity == null) {
            throw new IllegalArgumentException("Activity不能为null");
        }
        return new KeyboardHelper(activity, dialog, rootResId);
    }

    private KeyboardHelper(Ability activity, int rootResId) {
        this(activity, (activity != null && activity.findComponentById(rootResId) != null) ? activity.findComponentById(rootResId) : null);
    }

    private KeyboardHelper(Ability activity, Component contentView) {
        this(activity, null, contentView);
    }

    private KeyboardHelper(Ability activity, CommonDialog dialog, int rootResId) {
        this(activity, dialog, dialog != null && dialog.getContentCustomComponent().findComponentById(rootResId) == null ? dialog.getWindow().getCurrentComponentFocus().get().findComponentById(rootResId) : ((ComponentContainer) activity.getWindow().getCurrentComponentFocus().get().findComponentById(rootResId)));
    }

    private KeyboardHelper(Ability activity, CommonDialog dialog, Component contentView) {
        this.mActivity = new WeakReference<>(activity);
        this.mContentView = new WeakReference(contentView);
        checkNull();
        register();
        Window window = dialog != null ? dialog.getWindow() : activity.getWindow();
        Component mContentView = contentView != null ? contentView : window.getCurrentComponentFocus().get().findComponentById(rootResId);
        mPaddingBottom = mContentView.getPaddingBottom();
    }

    private KeyboardHelper(Ability activity, Window window) {
        this.mActivity = new WeakReference<>(activity);
        checkNull();
        register();
        ComponentContainer frameLayout = (ComponentContainer) activity.findComponentById(rootResId);
        Component contentView = frameLayout != null && frameLayout.getComponentAt(0) != null ? frameLayout.getComponentAt(0) : frameLayout;
        mPaddingBottom = contentView.getPaddingBottom();
        this.mContentView = new WeakReference<>(contentView);
    }

    private void checkNull() {
        if (mActivity == null) {
            throw new IllegalArgumentException("Activity不能为null");
        }
    }

    private void register() {
        Ability activity = mActivity.get();
        if (activity == null) {
            return;
        }
        activity.getLifecycle().addObserver(new LifecycleObserver() {
            @Override
            public void onStop() {
                super.onStop();
                Ability current = mActivity.get();
                //被系统回收后还可以恢复
                if (current == null || current != activity || ! current.isTerminating()) {
                    return;
                }
                //移除监听
                activity.getLifecycle().removeObserver(this);
                destroy();
            }

            @Override
            public void onActive() {
                super.onActive();
                //部分手机在打开状态下息屏后软键盘自动关闭没有收到相应监听--测试得为华为手机
                if (mIsKeyboardOpened) {
                    Component focusView = activity.findComponentById(rootResId);
                    if (focusView instanceof TextField) {
                        openKeyboard((TextField) focusView);
                    } else {
                        closeKeyboard(activity);
                    }
                }
            }
        });
    }

    /**
     * 是否打印log
     *
     * @param logEnable
     * @return KeyboardHelper
     */
    public KeyboardHelper setLogEnable(boolean logEnable) {
        mLogEnable = logEnable;
        return this;
    }

    /**
     * 设置软键盘开关状态转换回调--即有软键盘开关变化才会回调
     *
     * @param listener
     * @return KeyboardHelper
     */
    public KeyboardHelper setOnKeyboardVisibilityChangedListener(OnKeyboardVisibilityChangedListener listener) {
        this.mOnKeyboardVisibilityChangedListener = listener;
        return this;
    }

    /**
     * 监听layout变化
     *
     * @param focusResId （必须传入需要监听的TextField 的ID）
     * @return KeyboardHelper
     */
    public KeyboardHelper setEnable(int focusResId) {
        this.focusResId = focusResId;
        setEnable();
        return this;
    }


    /**
     * 设置监听
     *
     * @param
     * @return KeyboardHelper
     */
    private KeyboardHelper setEnable() {
        Ability activity = mActivity.get();
        if (activity == null) {
            return this;
        }
        activity.getWindow().setInputPanelDisplayType(WindowManager.LayoutConfig.INPUT_STATE_HIDDEN | WindowManager.LayoutConfig.INPUT_ADJUST_RESIZE | WindowManager.LayoutConfig.INPUT_ADJUST_PAN);
        // 当在一个视图树中全局布局发生改变或者视图树中的某个视图的可视状态发生改变时,所要调用的回调函数的接口类
//        activity.findComponentById(focusResId).getComponentTreeObserver().addGlobalFocusUpdatedListener(onGlobalLayoutListener);

        // 当在一个软键盘弹出视图发生变化调用
        ((KeyBoardContainer) activity.findComponentById(rootResId)).setKeyBoardListener(mKeyBoardListener);
        return this;
    }

    /**
     * 取消监听
     *
     * @return KeyboardHelper
     */
    public KeyboardHelper setDisable() {
        setDisable(mKeyMode);
        return this;
    }

    /**
     * 取消监听
     *
     * @param mode
     * @return KeyboardHelper
     */
    private KeyboardHelper setDisable(int mode) {
        Ability activity = mActivity.get();
        if (activity == null) {
            return this;
        }
        activity.getWindow().setInputPanelDisplayType(mode);
//        activity.findComponentById(focusResId).getComponentTreeObserver().removeGlobalFocusUpdatedListener(onGlobalLayoutListener);
        return this;
    }

    /**
     * 设置软键盘弹出隐藏监听回调
     */
    public KeyBoardListener mKeyBoardListener = new KeyBoardListener() {

        private final Rect r = new Rect();
        private int visibleThreshold = 0;
        private int mRootHeight = 0;

        @Override
        public void listener(int rootHeight) {

            if (mRootHeight < rootHeight) {
                mRootHeight = rootHeight;
            }
            Ability activity = mActivity.get();
            Component contentView = mContentView.get();
            if (visibleThreshold <= 0) {
                Context context = activity.getContext();
                Display display = DisplayManager.getInstance().getDefaultDisplay(context).get();

                visibleThreshold = (int) Math.round(KEYBOARD_VISIBLE_THRESHOLD_DP * (double)display.getAttributes().densityPixels + 0.5d);
            }
            //获取当前窗口可视区域大小的
            contentView.getWindowVisibleRect(r);
//            int heightDiff = height - r.bottom;
            int heightDiff = mRootHeight - rootHeight;
//            int heightDiff = contentView.getHeight()
            boolean isOpen = heightDiff > visibleThreshold;
//            heightDiff -= StatusBarUtil.getStatusBarHeight(mActivity.get().getContext());// NavigationBarUtil.getFakeNavigationBarHeight(activity);
//            heightDiff -= StatusBarUtil.getStatusBarHeight(mActivity.get().getContext()); //NavigationBarUtil.getRealNavigationBarHeight(activity);
            //
            if (isOpen == mIsKeyboardOpened && ! isOpen) {
                return;
            }
            if (heightDiff == mHeightDiff) {
                return;
            }
            //避免Activity多少初始化造成paddingBottom累加--一般paddingBottom不会超过软键盘高度
            if (isOpen) {
                mPaddingBottom = mPaddingBottom % heightDiff;
            }
            mIsKeyboardOpened = isOpen;
            mHeightDiff = heightDiff;

//            contentView.setPadding(contentView.getPaddingLeft(), contentView.getPaddingTop(), contentView.getPaddingRight(), mPaddingBottom + heightDiff);

            if (mOnKeyboardVisibilityChangedListener != null) {
                boolean remove = mOnKeyboardVisibilityChangedListener.onKeyboardVisibilityChanged(activity, isOpen, heightDiff, 0/*StatusBarUtil.getStatusBarHeight(mActivity.get().getContext())*//* NavigationBarUtil.getNavigationBarHeight(activity)*/);
                if (remove) {
//                    activity.findComponentById(focusResId).getComponentTreeObserver().removeGlobalFocusUpdatedListener(this);
                }
            }
        }
    };

    /**
     * 弃用，在这里效果不对
     * <p>
     * 设置View变化监听
     */
    public ComponentTreeObserver.GlobalFocusUpdatedListener onGlobalLayoutListener = new ComponentTreeObserver.GlobalFocusUpdatedListener() {

        private final Rect r = new Rect();
        private int visibleThreshold = 0;

        @Override
        public void onGlobalFocusUpdated(Component component, Component component1) {
            Ability activity = mActivity.get();
            int height = DisplayManager.getInstance().getDefaultDisplay(activity.getContext()).get().getAttributes().height;
            Component contentView = mContentView.get();
            if (visibleThreshold <= 0) {
                Context context = activity.getContext();
                Display display = DisplayManager.getInstance().getDefaultDisplay(context).get();

                visibleThreshold = (int) Math.round(KEYBOARD_VISIBLE_THRESHOLD_DP * (double)display.getAttributes().densityPixels + 0.5d);
            }
            //获取当前窗口可视区域大小的
            contentView.getWindowVisibleRect(r);
            int heightDiff = height - r.bottom;

//            int heightDiff = contentView.getHeight()
            boolean isOpen = heightDiff > visibleThreshold;
            heightDiff -= StatusBarUtil.getStatusBarHeight(mActivity.get().getContext());// NavigationBarUtil.getFakeNavigationBarHeight(activity);
            heightDiff -= StatusBarUtil.getStatusBarHeight(mActivity.get().getContext()); //NavigationBarUtil.getRealNavigationBarHeight(activity);
            //

            if (isOpen == mIsKeyboardOpened && ! isOpen) {
                return;
            }
            if (heightDiff == mHeightDiff) {
                return;
            }
            //避免Activity多少初始化造成paddingBottom累加--一般paddingBottom不会超过软键盘高度
            if (isOpen) {
                mPaddingBottom = mPaddingBottom % heightDiff;
            }
            mIsKeyboardOpened = isOpen;
            mHeightDiff = heightDiff;
//            contentView.setPadding(contentView.getPaddingLeft(), contentView.getPaddingTop(), contentView.getPaddingRight(), mPaddingBottom + heightDiff);

            if (mOnKeyboardVisibilityChangedListener != null) {
                boolean remove = mOnKeyboardVisibilityChangedListener.onKeyboardVisibilityChanged(activity, isOpen, heightDiff, 0);/* NavigationBarUtil.getNavigationBarHeight(activity)*/
                if (remove) {
                    activity.findComponentById(focusResId).getComponentTreeObserver().removeGlobalFocusUpdatedListener(this);
                }
            }
        }

    };

    @Override
    public void onSoftKeyBoardShowModeChanged(SoftKeyBoardController softKeyBoardController, int i) {
    }

    protected void destroy() {
        setDisable();
        mOnKeyboardVisibilityChangedListener = null;
        mActivity = null;
        mContentView = null;
    }

    /**
     * 关闭软键盘
     * @param view view
     */
    public static void closeKeyboard(Component view) {
        if (view != null) {
//            view.requestFocus();
//            view.simulateClick();
            view.clearFocus();
        }
        isKeyboardVisible = false;
    }

    /**
     * 关闭activity中打开的键盘
     *
     * @param activity
     */
    public static void closeKeyboard(Ability activity) {
        Component view = activity.getWindow().getCurrentComponentFocus().get();
        closeKeyboard(view);
    }

    /**
     * 关闭dialog中打开的键盘
     *
     * @param dialog
     */
    public static void closeKeyboard(CommonDialog dialog) {
        Component view = dialog.getWindow().getCurrentComponentFocus().get();
        closeKeyboard(view);
    }

    /**
     * 打开键盘
     *
     * @param editText
     * @param delay
     */
    public static void openKeyboard(final TextField editText, long delay) {
        if (editText == null) {
            return;
        }
        delay = delay <= 0 ? KEYBOARD_SHOW_DELAY_TIME : delay;
        new EventHandler(EventRunner.getMainEventRunner()).postTask(new Runnable() {
            @Override
            public void run() {
                editText.requestFocus();
                editText.setSelectionColor(new Color(0xffff0000));
                editText.simulateClick();
                isKeyboardVisible = true;
            }
        }, delay);
    }

    /**
     * 打开键盘
     *
     * @param editText
     */
    public static void openKeyboard(TextField editText) {
        openKeyboard(editText, KEYBOARD_SHOW_DELAY_TIME);
    }

    /**
     * 切换键盘的显示与隐藏
     * TODO 弃用  SoftKeyBoardController 系统未实现
     *
     * @param activity
     */
    public static void toggleKeyboard(Ability activity) {
        ((AccessibleAbility) activity).getSoftKeyBoardController();
//        Component currentFocus = activity.getAbility().getCurrentFocus();
//        InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
//        if (inputMethodManager.isActive()) {
//            inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
//        }
    }

    /**
     * 处理点击非 EditText 区域时，自动关闭键盘
     *
     * @param isAutoCloseKeyboard 是否自动关闭键盘
     * @param currentFocusView 当前获取焦点的控件
     * @param motionEvent 触摸事件
     * @param dialogOrActivity Dialog 或 Ability
     */
    public static void handleAutoCloseKeyboard(boolean isAutoCloseKeyboard, Component currentFocusView, TouchEvent motionEvent, Object dialogOrActivity) {
        if (isAutoCloseKeyboard && motionEvent.getAction() == TouchEvent.PRIMARY_POINT_DOWN && currentFocusView != null && (currentFocusView instanceof TextField) && dialogOrActivity != null) {
            int[] leftTop = {0, 0};
            leftTop[0] = currentFocusView.getLeft();
            leftTop[1] = currentFocusView.getTop();
            int left = leftTop[0];
            int top = leftTop[1];
            int bottom = top + currentFocusView.getHeight();
            int right = left + currentFocusView.getWidth();
            MmiPoint pointer = motionEvent.getPointerPosition(motionEvent.getIndex());
            if (! (pointer.getX() > left && pointer.getX() < right && pointer.getY() > top && pointer.getY() < bottom)) {
                if (dialogOrActivity instanceof CommonDialog) {
                    closeKeyboard((CommonDialog) dialogOrActivity);
                } else if (dialogOrActivity instanceof Ability) {
                    closeKeyboard((Ability) dialogOrActivity);
                }
            }
        }
    }
}
